Friday, June 19, 2009
Sample Grid CSS
background:#FFF;
border:1px solid #444;
display:none;
width:150px;
}
#myMenu ul, #myMenu ul * {
padding:0;
margin:0;
}
#myMenu ul li{
list-style:none;
border:1px solid #444;
padding: 5px;
display:block;
}
#myMenu ul li:hover{
background:#666;
color:#FFF;
}
#myMenu ul li:hover span{
color:#FFF;
}
#myMenu li:hover a{
color:#FFF;
}
#myMenu a{
color:#000;
font:11px Tahoma;
font-weight:bold;
text-decoration:none;
}
#myMenu2 {
background:#600;
border:1px solid #200;
color:#FFF;
display:none;
width:150px;
}
#myMenu2 ul, #myMenu ul * {
padding:0;
margin:0;
}
#myMenu2 ul li{
list-style:none;
border:1px solid #200;
padding: 2px;
display:block;
}
#myMenu2 ul li:hover{
background:#C22;
color:#FFF;
}
#myMenu2 ul li:hover span{
color:#FFF;
}
#myMenu2 li:hover a{
color:#FFF;
}
#myMenu2 a{
color:#FFF;
font:11px Tahoma;
font-weight:bold;
text-decoration:none;
}
#myMenu2 a:hover{
color:#FFF;
font:11px Tahoma;
font-weight:bold;
text-decoration:underline;
}
div.container
{
border: none;
border-collapse: collapse;
/*margin-top: 50px;
margin-left:20px;*/
float:left;
position:relative;
width:100%;
height:100%;
}
div.container *
{
font: 11px Tahoma;
}
div.mygrid_toolbar
{
width: 100%;
height: 30px;
border: none;
}
div.mygrid_toolbar_item
{
border: none;
width: 24px;
height: 24px;
float: left;
display: none;
}
div.mygrid_toolbar_submenu
{
border: none;
width: 8px;
height: 24px;
float: left;
display: none;
background: #ECE9D8 url('../css/image/mygrid_down.png') no-repeat center center;
}
div.mygrid_toolbar_add
{
background: #ECE9D8 url('../css/image/mygrid_add.png') no-repeat center center;
}
div.mygrid_toolbar_delete
{
background: #ECE9D8 url('../css/image/mygrid_delete.png') no-repeat center center;
}
div.mygrid_toolbar_move_up
{
background: #ECE9D8 url('../css/image/mygrid_move_up.png') no-repeat center center;
}
div.mygrid_toolbar_move_down
{
background: #ECE9D8 url('../css/image/mygrid_move_down.png') no-repeat center center;
}
div.mygrid_toolbar_move_left
{
background: #ECE9D8 url('../css/image/mygrid_move_left.png') no-repeat center center;
}
div.mygrid_toolbar_move_right
{
background: #ECE9D8 url('../css/image/mygrid_move_right.png') no-repeat center center;
}
table.mygrid
{
width: 600px;
table-layout:fixed;
border: solid 1px #cccc99;
border-collapse: collapse;
cursor:default;
float:left;
position:relative;
}
/*disabling white space wrapping, if IE7 for TH we must use
th {
white-space: pre;
}
*/
table.mygrid td {
border: 1px solid #ABABAB;
padding: 2px;
text-align: left;
white-space: nowrap;
overflow: hidden;
}
.mygrid_GlobalTopCell, .mygrid_GlobalColumnHeaderCell, .mygrid_GlobalRowHeaderCell
/*thead td*/
{
background-color: #ECE9D8;
border: 1px solid #black;
height: 20px;
width: 20px;
}
.resizeBar
{
float: right;
cursor: e-resize;
width: 5px;
height: 15px;
background-color: #5C5C5C;
}
.moveBar
{
display: none;
background-color: #66AADD;
width: 2px;
height: 100px;
position:absolute;
z-index: 50;
}
.unselectable
{
-moz-user-select: none;
}
.mygrid_BodyCell
{
width: 100px;
}
.col-resize
{
cursor: col-resize;
}
.sorted_asc
{
background: #ECE9D8 url('../css/image/arrow_up.png') no-repeat center center;
}
.sorted_desc
{
background: #ECE9D8 url('../css/image/arrow_down.png') no-repeat center center;
}
.mygrid_HeaderCell
{
background-color: #DCDCDC;
}
.selected
{
background-color: #B4D5F1;
}
.selectedGlobalHeader
{
background-color: #EAA770;
}
.edit
{
padding: 0px;
}
.mygrid_TextBox
{
width: 100%;
height: 100%;
display: none;
}
Sample Grid
{
//*************************************************************************************************************************
//*************************************************************************************************************************
// INITIALIZE PARAMETERS
//*************************************************************************************************************************
//*************************************************************************************************************************
var data = d;
var s = {
mode : 'edit', //values: edit, display
totalWidth : 220,
colNum : 2,
colWidths : ['50%', '50%'],
hasData : false,
hasHeader : false,
hasBody : false,
colResize : false,
col : {
n : -1,
c : null, //the current resize column object
nc : null, //the next column object
//g : null, //the current resize colgroup's col object
ow : 0, //resize column original Width
ox : 0, //resize column original X
ncow : 0 //next column original width
}
};
$.extend(s, settings);
if (data)
{
if (data.header)
{
if (data.header.length > 0)
{
s.hasData = true;
s.hasHeader = true;
s.colNum = data.header[0].length;
}
}
if (data.body)
{
if (data.body.length > 0)
{
s.hasData = true;
s.hasBody = true;
s.colNum = data.body[0].length;
}
}
}
//*************************************************************************************************************************
//*************************************************************************************************************************
// INITIALIZE CONTAINER, TOOLBAR & TABLE
//*************************************************************************************************************************
//*************************************************************************************************************************
//initialize container and table
var $container = $(this);
var $toolbar = $('').addClass('mygrid_toolbar').appendTo($container);
var $table = $("
$table.width(s.totalWidth).addClass('unselectable');
//*************************************************************************************************************************
//*************************************************************************************************************************
// TOOLBAR
//*************************************************************************************************************************
//*************************************************************************************************************************
var $toolbar_add = $('').addClass('mygrid_toolbar_item').addClass('mygrid_toolbar_add').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Too many objects selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalColumnHeaderCell'))
{
var columnIndex = this.cellIndex;
$('tr', $table).each(function(row) {
var $thisCell = $('td', this).filter(':eq('+columnIndex+')');
$thisCell.clone(true).html('').insertAfter($thisCell);
});
$('td', $gcHeaderRow).filter(':eq('+(columnIndex+1)+')').html('');
}
else if ($(this).hasClass('mygrid_GlobalRowHeaderCell'))
{
var $thisRow = $(this).parent();
$thisRow.clone(true).children('td').each(function() { $(this).html(''); }).end().insertAfter($thisRow);
}
});
func_clearToolbar();
});
var $toolbar_add_submenu = $('').addClass('mygrid_toolbar_submenu').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Too many objects selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalColumnHeaderCell'))
{
var columnIndex = this.cellIndex;
$('tr', $table).each(function(row) {
var $thisCell = $('td', this).filter(':eq('+columnIndex+')');
$thisCell.clone(true).html('').insertAfter($thisCell);
});
}
else if ($(this).hasClass('mygrid_GlobalRowHeaderCell'))
{
var $thisRow = $(this).parent();
$thisRow.clone(true).children('td').each(function() { $(this).html(''); }).end().insertAfter($thisRow);
}
});
func_clearToolbar();
});
var $toolbar_delete = $('').addClass('mygrid_toolbar_item').addClass('mygrid_toolbar_delete').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Too many objects selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalColumnHeaderCell'))
{
var columnIndex = this.cellIndex;
$('tr', $table).each(function(row) { $('td', this).filter(':eq('+columnIndex+')').remove();});
}
else if ($(this).hasClass('mygrid_GlobalRowHeaderCell'))
{
//var rowIndex = $(this).parent().get(0).rowIndex;
$(this).parent().remove();
}
});
func_clearToolbar();
});
var $toolbar_move_up = $('').addClass('mygrid_toolbar_item').addClass('mygrid_toolbar_move_up').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Only one Column or Row can be selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalRowHeaderCell'))
{
$(this).parent().insertBefore($(this).parent().prev());
}
});
//func_clearToolbar();
});
var $toolbar_move_down = $('').addClass('mygrid_toolbar_item').addClass('mygrid_toolbar_move_down').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Only one Column or Row can be selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalRowHeaderCell'))
{
$(this).parent().insertAfter($(this).parent().next());
}
});
//func_clearToolbar();
});
var $toolbar_move_left = $('').addClass('mygrid_toolbar_item').addClass('mygrid_toolbar_move_left').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Only one Column or Row can be selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalColumnHeaderCell'))
{
var columnIndex = this.cellIndex;
$('tr', $table).each(function(row) {
var $thisCell = $('td', this).filter(':eq('+columnIndex+')');
$thisCell.insertBefore($thisCell.prev());
});
}
});
//func_clearToolbar();
});
var $toolbar_move_right = $('').addClass('mygrid_toolbar_item').addClass('mygrid_toolbar_move_right').appendTo($toolbar)
.click(function() {
var $collection = $('td.selectedGlobalHeader', $table);
if ($collection.length != 1) { alert('Only one Column or Row can be selected.'); return; }
$collection.each(function() {
if ($(this).hasClass('mygrid_GlobalColumnHeaderCell'))
{
var columnIndex = this.cellIndex;
$('tr', $table).each(function(row) {
var $thisCell = $('td', this).filter(':eq('+columnIndex+')');
$thisCell.insertAfter($thisCell.next());
});
}
});
//func_clearToolbar();
});
//*************************************************************************************************************************
//*************************************************************************************************************************
// DATA
//*************************************************************************************************************************
//*************************************************************************************************************************
// COLGROUP to define Column Widths
/*
$gcGroup = $('
$gcGroup.attr('span', s.colNum);
$('
if (s.colWidths.length == s.colNum)
{
$.each(s.colWidths, function(i, v) {
$('
});
}
*/
//GLOBAL COLUMN HEADER
var $gcHeader = $("").appendTo($table);
var $gcHeaderRow = $("
// add the most top-left cell
var $gcTopCell = $("
for (var i=0; i
$("
.width(s.totalWidth*parseFloat(s.colWidths[i])/100);
}
if (s.hasData)
{
if (s.hasHeader)
{
//add the grid header as a TBODY
$header = $("").attr('id', 'mygrid_Header').appendTo($table);
$.each(data.header,
function(i, r) {
//add a new header row
var $row = $("
//for the new header row, add a global row header cell
$("
//inside the new header row, create cells
$.each(r, function(j, c) {
$("
});
}
if (s.hasBody)
{
//add the grid body as a TBODY
$body = $("").attr('id', 'mygrid_Body').appendTo($table);
$.each(data.body,
function(i, r) {
var $row = $("
//for the new row, add a Global Row Header Cell
$("
$.each(r, function(j, c) { $("
});
}
}
else //if no data passed in
{
$header = $("").attr('id', 'mygrid_Header').appendTo($table);
$("
.append($("
.append($("
.append($("
$body = $("").attr('id', 'mygrid_Body').appendTo($table);
$("
.append($("
.append($("
.append($("
}
//*************************************************************************************************************************
//*************************************************************************************************************************
// BIND EVENTS
//*************************************************************************************************************************
//*************************************************************************************************************************
//general function to clear
var func_clear=function() {
$('td.edit', $table).each(function() {
var cellValue = $('.mygrid_TextBox', this).eq(0).val();
$(this).empty().html(cellValue);
} );
$('td', $table).removeClass('selected').removeClass('selectedGlobalHeader').removeClass('edit');
func_clearToolbar();
};
//general to clear toolbar
var func_clearToolbar=function() {
$('div.mygrid_toolbar_item', $toolbar).hide();
};
//##################################### RESIZE - BEGIN################################
var $moveBar = $('').addClass('moveBar').appendTo($('body'));
$gcHeader.mousedown(function(e) {
var $t = $(e.target);
if ($t.hasClass('resizeBar'))
{
s.colResize = true;
var _bar = $t;
var _col = _bar.parent();
s.col.n = $('div.resizeBar').index(_bar);
s.col.c = _col;
s.col.nc = _col.next();
//s.col.g = $gcGroup.children('col').eq(s.col.n+1);
s.col.ow = _col.width();
s.col.ox = e.pageX;
s.col.ncow = _col.next().width();
$moveBar.css('left', s.col.ox).css('top', _col.parent().offset().top+'px').height($table.height()).show();
//$table.addClass('unselectable');
//('body').bind('select', function() { return false; });
//$('#log').html($moveBar.css('left') + '---'+$moveBar.css('top')+'--'+JSON.stringify(_col.parent().offset()));
}
});
$(document)
.mousemove(function(e) {
if (s.colResize)
{
//$gcGroup.children('col').eq(s.col.n+1).attr('width', s.col.ow + _diff);
//s.col.c.width( s.col.ow + _diff);
//s.col.nc.width(s.col.ncow - _diff);
if (s.col.nc.length>0)
{
var _diff = e.pageX - s.col.ox; //the new width, original width + different
$moveBar.css('left', s.col.ox + _diff);
}
//$table.width(s.totalWidth + _diff);
}
})
.mouseup(function(e) {
if (s.colResize)
{
var _diff = parseInt(e.pageX) - parseInt(s.col.ox);
//$table.width(s.totalWidth + _diff);
var _nw = s.col.ow + _diff;
var _ncnw = s.col.ncow - _diff;
if (_nw > 20 && _ncnw > 20)
{
s.col.nc.width(_ncnw);
s.col.c.width(_nw);
}
//$table.width(s.totalWidth);
s.colResize = false;
//s.totalWidth = $table.width();
s.col.n = -1;
s.col.ow = 0;
s.col.ox = 0;
$moveBar.hide();
//$table.removeClass('unselectable');
}
})
.bind('selectstart', function(e) {
if (s.colResize)
{
return false;
}
});
//##################################### RESIZE - END#####################################
var $cellinput = $('').addClass('mygrid_TextBox').appendTo($('body'));
$table
.click(function(e) {
var t = e.target;
var $t = $(t);
if ($t.hasClass('mygrid_GlobalColumnHeaderCell')) //highlight the column when clicking on column header
{
func_clear();
var column = t.cellIndex;
$('tr', $table).each(function(row) { $('td', this).filter(':eq('+column+')').addClass('selected');});
$t.removeClass('selected').addClass('selectedGlobalHeader');
func_clearToolbar();
$toolbar_move_left.show();
$toolbar_move_right.show();
$toolbar_delete.show();
$toolbar_add.show();
}
else if ($t.hasClass('mygrid_GlobalRowHeaderCell')) //highlight the row when clicking on the row header
{
func_clear();
$t.siblings().addClass('selected');
$t.removeClass('selected').addClass('selectedGlobalHeader');
func_clearToolbar();
$toolbar_move_up.show();
$toolbar_move_down.show();
$toolbar_delete.show();
$toolbar_add.show();
}
else if ($t.hasClass('mygrid_BodyCell')) //click: highlight the cell which users click on
{
func_clear();
$t.addClass('selected');
//highlight global row header
$t.siblings('.mygrid_GlobalRowHeaderCell').addClass('selectedGlobalHeader');
//highlight global column header
var column = t.cellIndex;
$('td', $gcHeaderRow).filter(':eq('+column+')').addClass('selectedGlobalHeader');
}
})
.dblclick(function(e) {
var t = e.target;
var $t = $(t);
if ($t.hasClass('mygrid_BodyCell')) //double-click: highlight the cell which users click on and also create a text box;
{
var $cell = $t;
$cellinput.val($cell.html());
$.blockUI({ message: $cellinput,
css: { left: $cell.offset().left + 'px', top: $cell.offset().top + 'px',
width: $cell.width() + 'px', height: $cell.height() + 'px',
textAlign: 'left' },
overlayCSS: { opacity: 0.3 }
});
$('.blockOverlay').attr('title','Click to quit edit mode').click(function() {
$cell.html($cellinput.val());
$.unblockUI();
});
}
else if ($t.hasClass('mygrid_GlobalColumnHeaderCell')) //sort the column when double-clicking on column header
{
func_clear();
var sortDirection;
if ($t.hasClass('sorted_asc')) sortDirection = -1;
else if ($t.hasClass('sorted_desc')) sortDirection = 0;
else sortDirection = 1;
$("td.mygrid_GlobalColumnHeaderCell", $table).removeClass('sorted_asc').removeClass('sorted_desc');
var column = t.cellIndex;
var rows = $('tr', $body).each(function(i) { $(this).data('defaultKey', i); }).get();
$.each(rows, function(i, row) {
var key = $(row).children('td').eq(column).text().toUpperCase();
var numericKey = parseFloat(key);
key = isNaN(numericKey) ? key : numericKey;
$(row).data('sortKey', key);
});
if (sortDirection == 0)
{
rows.sort(function(a, b) {
if ($(a).data('defaultKey') < $(b).data('defaultKey')) return -1;
if ($(a).data('defaultKey') > $(b).data('defaultKey')) return 1;
return 0;
});
}
else
{
rows.sort(function(a, b) {
if ($(a).data('sortKey') < $(b).data('sortKey')) return -sortDirection;
if ($(a).data('sortKey') > $(b).data('sortKey')) return sortDirection;
return 0;
});
}
$.each(rows, function(i, row) {
$body.append(row);
$(row).removeData('sortKey');
});
if (sortDirection == 1)
$t.removeClass('sorted_desc').addClass('sorted_asc');
else if (sortDirection == -1)
$t.removeClass('sorted_asc').addClass('sorted_desc');
else
$t.removeClass('sorted_asc').removeClass('sorted_desc');
$('tr', $table).each(function(row) { $('td', this).filter(':eq('+column+')').addClass('selected');});
$t.removeClass('selected').addClass('selectedGlobalHeader');
}
});
};
Friday, June 5, 2009
Friday, May 15, 2009
Article: Absolutely relative
from http://www.wpdfd.com/issues/78/absolutely_relative
Absolutely relative
The concepts of absolute and relative positioning in CSS can be quite confusing and are often misunderstood.
Absolute positioning puts CSS boxes (divs) at specific pixel locations in the browser window, just like pinning cards on a notice board. Usually, the absolute position is measured from the top left corner of the page but it doesn't have to be, as you will see.
For relative positioning, the analogy I often use is that of polystyrene blocks in a swimming pool – they float until they are pushed downwards by another one from above. If you specify float: left or float: right, that makes them float horizontally instead of vertically.
Used exclusively, absolutely positioned divs produce hard, static layouts which invariably break in the plethora of screen sizes we have to contend with.
Relatively positioned layouts, on the other hand, can adjust to the size and shape of the browser window and are much more likely to give satisfactory results on the maximum number of systems – but that means the actual layouts are less predictable and sometimes get just plain silly when the lines of text get too long.
By combining relative and absolute positioning, you get more control without losing the flexibility. The key to this is the fact that absolutely positioned boxes don't have to be placed relative to the browser's edges, they can be positioned relative to any div you put them in.
If you put an absolutely positioned box inside a relatively positioned box, it moves with that box. It is absolutely relative!
It's just like walking around inside a plane. The plane is travelling relative to the airport but when you move around inside it, you seem to be at some point, say, six feet away from your seat and two feet to the left.
Apart from the wisdom of having layouts that are less likely to break, this also opens up a whole new set of possibilities. You can put images or captions next to blocks of text and they stay there. Unlike the rectangular constraints imposed by using tables, these 'satellite' divs can go anywhere in a complete 360° arc around the text – or over or behind it.
Keep things flexible
I try to avoid the top-left way of thinking that many designers seem to embrace by default. I like to float my content in the horizontal centre of the page so that it looks balanced on any monitor and not lop-sided. To do this, you can specify right and left margins and let the content stretch or specify the content width and let the margins take up the slack. To keep Internet Explorer happy, it is also necessary to put the entire page inside
That's just one way of doing it. It works fine for all monitors 800 x 600 or larger. If you need to accommodate smaller screens, you can use percentages.
Having established a 'page' div, I just put relatively positioned rows one above another much like the rows in a table. Inside each row are three columns. col1 holds the vertical section headings, col2 is for headings and pictures and col3 is the main text. The height of each row is determined by the amount of text in col3.
A box's z-index property controls the layering. Most of the time, you don't have to be too concerned about z-index. Absolutely position boxes adopt their z-index values automatically based upon the position of the div in the markup – the further down in the markup, the higher its layer will be.
Sometimes, you might want to manipulate the z-index value if the default is not giving the effect you want. All you have to do is to make sure that the frontmost box has a higher z-index value. You don't have to change z-index values in steps of 1. In fact, it is better to give them steps of 10 or 100 in case you want to put something in between at a later date.
So, now you have an image that can be positioned anywhere around a text box, behind or in front. You can also play that trick the other way round. If you want to add a small caption to an image, put the .textpanel inside the .picbox. In this instance, you should probably set the width and height of .picbox and the width of .textpanel to a value smaller than .picbox width. If you want the caption to overprint the picture totally or partly, just place it wherever you like inside .picbox.
Then, you can do both and go all the way. Make the picture relative to the textpanel AND make the caption relative to the picture.
Experiment! Once you start playing with these techniques you will find all kinds of interesting layout possibilities.
About the styles
For all these examples, I have created basic classes in the main stylesheet in the head section of this page. I then modified those styles locally using 'inline' styling for their margin-left and margin-top properties. Have a look at the source.
Monday, May 11, 2009
How to dynamically compress JavaScript files and CSS files?
If web page uses too much JavaScript files and CSS files, it takes time to load every file to client side, especially if using HTTPS. The code below shows how to compress all JavaScript and CSS files into one download to Client side, which saves bandwidth and loading speed.
The idea is actually add a new httpHandlers.
First, in the web.config, add code below to the system.web section.
Second, in the .aspx page, other than add reference to JavaScript files or CSS files, use the code below instead.
<%= customLibrary.ScriptCombiner.GetScriptTags("ElementEditor") %>
Here, "customLibrary" is your own library, "ScriptCombiner" is a class in your library, "GetScriptTags" is a function to do the job.
using System;
using System.IO;
using System.Text;
using System.Web;
public class ScriptCombiner : IHttpHandler
{
private readonly static TimeSpan CACHE_DURATION = TimeSpan.FromDays(30);
private HttpContext context;
public void ProcessRequest(HttpContext context)
{
this.context = context;
HttpRequest request = context.Request;
// Read setName, version from query string
string setName = (request["s"]!=null)?request["s"]:string.Empty;
string version = (request["v"]!=null)?request["v"]:string.Empty;
// Decide if browser supports compressed response
bool isCompressed = this.CanGZip(context.Request);
// If the set has already been cached, write the response directly from
// cache. Otherwise generate the response and cache it
if (!this.WriteFromCache(setName, version, isCompressed))
{
using (MemoryStream memoryStream = new MemoryStream(8092))
{
// Decide regular stream or gzip stream based on whether the response can be compressed or not
//using (Stream writer = isCompressed ? (Stream)(new GZipStream(memoryStream, CompressionMode.Compress)) : memoryStream)
using (Stream writer = isCompressed ? (Stream)(new ICSharpCode.SharpZipLib.GZip.GZipOutputStream(memoryStream)) : memoryStream)
{
// Read the files into one big string
StringBuilder allScripts = new StringBuilder();
foreach (string fileName in GetScriptFileNames(setName))
allScripts.Append(this.readAllText(context.Server.MapPath(fileName)));
// Minify the combined script files and remove comments and white spaces
JavaScriptMinifier minifier = new JavaScriptMinifier();
string minified = minifier.Minify(allScripts.ToString());
// Send minfied string to output stream
byte[] bts = Encoding.UTF8.GetBytes(minified);
writer.Write(bts, 0, bts.Length);
}
// Cache the combined response so that it can be directly written
// in subsequent calls
byte[] responseBytes = memoryStream.ToArray();
context.Cache.Insert(GetCacheKey(setName, version, isCompressed),
responseBytes, null, System.Web.Caching.Cache.NoAbsoluteExpiration,
CACHE_DURATION);
// Generate the response
this.WriteBytes(responseBytes, isCompressed);
}
}
}
private string readAllText(string filePath)
{
StreamReader reader = new StreamReader(filePath, System.Text.Encoding.Default);
byte[] data=Encoding.Default.GetBytes(reader.ReadToEnd());
reader.Close();
//return (new ASCIIEncoding()).GetString(data);
return (new UTF8Encoding()).GetString(data);
}
private bool WriteFromCache(string setName, string version, bool isCompressed)
{
byte[] responseBytes = context.Cache[GetCacheKey(setName, version, isCompressed)] as byte[];
if (responseBytes == null || responseBytes.Length == 0)
{
//irAutoLog.addLog("NoCache", "HttpCombiner." + setName + "." + version + "." + isCompressed);
return false;
}
//irAutoLog.addLog("GetCache", "HttpCombiner." + setName + "." + version + "." + isCompressed);
this.WriteBytes(responseBytes, isCompressed);
return true;
}
private void WriteBytes(byte[] bytes, bool isCompressed)
{
HttpResponse response = context.Response;
response.AppendHeader("Content-Length", bytes.Length.ToString());
response.ContentType = "application/x-javascript";
if (isCompressed)
response.AppendHeader("Content-Encoding", "gzip");
else
response.AppendHeader("Content-Encoding", "utf-8");
context.Response.Cache.SetCacheability(HttpCacheability.Public);
context.Response.Cache.SetExpires(DateTime.Now.Add(CACHE_DURATION));
context.Response.Cache.SetMaxAge(CACHE_DURATION);
response.ContentEncoding = Encoding.Unicode;
response.OutputStream.Write(bytes, 0, bytes.Length);
response.Flush();
}
private bool CanGZip(HttpRequest request)
{
string acceptEncoding = request.Headers["Accept-Encoding"];
if ((acceptEncoding!=null && acceptEncoding!=string.Empty) &&
(acceptEncoding.IndexOf("gzip")>-1 || acceptEncoding.IndexOf("deflate")>-1))
return true;
return false;
}
private string GetCacheKey(string setName, string version, bool isCompressed)
{
return "HttpCombiner." + setName + "." + version + "." + isCompressed;
}
public bool IsReusable
{
get { return true; }
}
// private helper method that return an array of file names inside the text file stored in App_Data folder
private static string[] GetScriptFileNames(string setName)
{
string[] fileNames = new string[] {};
switch (setName)
{
case "Reports":
fileNames = new string[2]
{
"js/jsGlobalReporting.js",
"js/jsReport_New.js"
};
break;
case "ReportViewer":
fileNames = new string[6]
{
"js/jsGlobalReporting.js",
"js/json.js",
"js/jsJSONObject.js",
"js/jsReportViewer_Grid_View.js",
"js/jsReportViewer_PageElement_Advanced.js",
"js/jsReportViewer_Advanced.js"
};
break;
case "ElementEditor":
fileNames = new string[6]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/jquery.grid.edit.js",
"js/json2.js",
"js/jsJSONObject.js",
"js/jsReportViewer_ElementEditor.js"
};
break;
case "PageEditor":
fileNames = new string[5]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsJSONObject.js",
"js/jsReportViewer_PageEditor.js"
};
break;
case "ReportSetup":
fileNames = new string[3]
{
"js/json.js",
"js/jsGlobalReporting.js",
"js/jsReportViewer_ReportSetup.js"
};
break;
case "FormViewer":
fileNames = new string[5]
{
"js/jquery-1.3.2.min.js",
"js/jquery-ui-1.7.1.custom.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsFormViewer.js"
};
break;
case "Forms":
fileNames = new string[4]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsForms.js"
};
break;
case "FormDesigner":
fileNames = new string[4]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsFormDesigner.js"
};
break;
case "SignOff":
fileNames = new string[4]
{
"js/jquery.min.js",
"js/jquery.fn.js",
"js/json2.js",
"js/jsReport_SignOff.js"
};
break;
}
return fileNames;
}
public static string GetScriptTags(string setName)
{
string result = null;
System.Version ver = irGlobal.getExecutingAssemblyVersion();
string version = (ver==null)?"100":ver.ToString();
//#if (DEBUG)
// foreach (string fileName in GetScriptFileNames(setName))
// {
// result += String.Format("\n", VirtualPathUtility.ToAbsolute(fileName), version);
// }
//#else
result += String.Format("", setName, version);
//#endif
return result;
}
}
Use JSMIN to dynamically minify javascript in C#
using System;
using System.IO;
using System.Text;
/* Originally written in 'C', this code has been converted to the C# language.
* The author's copyright message is reproduced below.
* All modifications from the original to C# are placed in the public domain.
*/
/* jsmin.c
2007-05-22
Copyright (c) 2002 Douglas Crockford (www.crockford.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
The Software shall be used for Good, not Evil.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
public class JavaScriptMinifier
{
const int EOF = -1;
StreamReader sr;
StreamWriter sw;
int theA;
int theB;
int theLookahead = EOF;
public string Minify(string src)
{
MemoryStream srcStream = new MemoryStream(Encoding.Unicode.GetBytes(src));
MemoryStream tgStream = new MemoryStream(8092);
using (sr = new StreamReader(srcStream, Encoding.Unicode))
{
using (sw = new StreamWriter(tgStream, Encoding.Unicode))
{
jsmin();
}
}
return Encoding.Unicode.GetString(tgStream.ToArray());
}
/* jsmin -- Copy the input to the output, deleting the characters which are
insignificant to JavaScript. Comments will be removed. Tabs will be
replaced with spaces. Carriage returns will be replaced with linefeeds.
Most spaces and linefeeds will be removed.
*/
void jsmin()
{
theA = '\n';
action(3);
while (theA != EOF)
{
switch (theA)
{
case ' ':
{
if (isAlphanum(theB))
{
action(1);
}
else
{
action(2);
}
break;
}
case '\n':
{
switch (theB)
{
case '{':
case '[':
case '(':
case '+':
case '-':
{
action(1);
break;
}
case ' ':
{
action(3);
break;
}
default:
{
if (isAlphanum(theB))
{
action(1);
}
else
{
action(2);
}
break;
}
}
break;
}
default:
{
switch (theB)
{
case ' ':
{
if (isAlphanum(theA))
{
action(1);
break;
}
action(3);
break;
}
case '\n':
{
switch (theA)
{
case '}':
case ']':
case ')':
case '+':
case '-':
case '"':
case '\'':
{
action(1);
break;
}
default:
{
if (isAlphanum(theA))
{
action(1);
}
else
{
action(3);
}
break;
}
}
break;
}
default:
{
action(1);
break;
}
}
break;
}
}
}
}
/* action -- do something! What you do is determined by the argument:
1 Output A. Copy B to A. Get the next B.
2 Copy B to A. Get the next B. (Delete A).
3 Get the next B. (Delete B).
action treats a string as a single character. Wow!
action recognizes a regular expression if it is preceded by ( or , or =.
*/
void action(int d)
{
if (d <= 1)
{
put(theA);
}
if (d <= 2)
{
theA = theB;
if (theA == '\'' || theA == '"')
{
for (; ; )
{
put(theA);
theA = get();
if (theA == theB)
{
break;
}
if (theA <= '\n')
{
throw new Exception(string.Format("Error: JSMIN unterminated string literal: {0}\n", theA));
}
if (theA == '\\')
{
put(theA);
theA = get();
}
}
}
}
if (d <= 3)
{
theB = next();
if (theB == '/' && (theA == '(' || theA == ',' || theA == '=' ||
theA == '[' || theA == '!' || theA == ':' ||
theA == '&' || theA == '|' || theA == '?' ||
theA == '{' || theA == '}' || theA == ';' ||
theA == '\n'))
{
put(theA);
put(theB);
for (; ; )
{
theA = get();
if (theA == '/')
{
break;
}
else if (theA == '\\')
{
put(theA);
theA = get();
}
else if (theA <= '\n')
{
throw new Exception(string.Format("Error: JSMIN unterminated Regular Expression literal : {0}.\n", theA));
}
put(theA);
}
theB = next();
}
}
}
/* next -- get the next character, excluding comments. peek() is used to see
if a '/' is followed by a '/' or '*'.
*/
int next()
{
int c = get();
if (c == '/')
{
switch (peek())
{
case '/':
{
for (; ; )
{
c = get();
if (c <= '\n')
{
return c;
}
}
}
case '*':
{
get();
for (; ; )
{
switch (get())
{
case '*':
{
if (peek() == '/')
{
get();
return ' ';
}
break;
}
case EOF:
{
throw new Exception("Error: JSMIN Unterminated comment.\n");
}
}
}
}
default:
{
return c;
}
}
}
return c;
}
/* peek -- get the next character without getting it.
*/
int peek()
{
theLookahead = get();
return theLookahead;
}
/* get -- return the next character from stdin. Watch out for lookahead. If
the character is a control character, translate it to a space or
linefeed.
*/
int get()
{
int c = theLookahead;
theLookahead = EOF;
if (c == EOF)
{
c = sr.Read();
}
if (c >= ' ' || c == '\n' || c == EOF)
{
return c;
}
if (c == '\r')
{
return '\n';
}
return ' ';
}
void put(int c)
{
sw.Write((char)c);
}
/* isAlphanum -- return true if the character is a letter, digit, underscore,
dollar sign, or non-ASCII character.
*/
bool isAlphanum(int c)
{
return ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') ||
(c >= 'A' && c <= 'Z') || c == '_' || c == '$' || c == '\\' ||
c > 126);
}
}
Use SharpZipLib to GZip in C#
using System;
using System.IO;
using ICSharpCode.SharpZipLib.Core;
using ICSharpCode.SharpZipLib.GZip;
public static byte[] Compress(byte[] buffer) {
MemoryStream ms = new MemoryStream();
Stream stream = new GZipOutputStream(ms, buffer.Length);
try {
stream.Write(buffer, 0, buffer.Length);
}
finally {
stream.Close();
}
return ms.ToArray();
}
public static byte[] Decompress(byte[] buffer) {
MemoryStream ms = new MemoryStream();
byte[] data = new byte[4096];
Stream stream = new GZipInputStream(new MemoryStream(buffer));
try {
while (true) {
int bytes = stream.Read(data, 0, data.Length);
if (bytes < 1) {
break;
}
ms.Write(data, 0, bytes);
}
}
finally {
stream.Close();
}
return ms.ToArray();
}